package uc

import (
	"context"
	"go.uber.org/zap"
	"google.golang.org/protobuf/proto"
	"strconv"
	"strings"
	"wzgames/internal/constant"
	"wzgames/internal/gmq"
	"wzgames/internal/model/gamep"
	"wzgames/internal/model/mcomm"
	"wzgames/internal/model/statement"
	"wzgames/internal/model/user"
	"wzgames/internal/response"
	"wzgames/pkg/logger"
)

type UCService struct {
}

func NewUCService() *UCService {
	return &UCService{}
}

// LoadBalance 获取余额信息
func (s *UCService) LoadBalance(ctx context.Context, req *user.BalanceReq, res *user.BalanceRet) error {
	if req.WalletType == mcomm.WalletType_DouWallet {
		code, wallet := WalletMgr().LoadWallet(req.AgtId, req.Uid, req.CurrId)
		if code != 0 {
			res.Code = int32(code)
			return nil
		}
		res.Balance = wallet.Balance
		res.Wv = wallet.Wv
		return nil
	}

	return nil
}

// ImResultBet 即时结算投注
func (s *UCService) ImResultBet(ctx context.Context, req *statement.PlayBet, res *user.BalanceRet) error {
	b, err := proto.Marshal(req)
	if err != nil {
		logger.Error("[UC] create im bet fail on proto.Marshal", zap.Uint64("BetId", req.BetId), zap.Error(err))
		res.Code = int32(response.ErrInternal)
		return nil
	}
	// 先发往MQ异步处理，成功后往下走
	if !gmq.Publish(constant.SubjectImBet, b) {
		res.Code = int32(response.ErrInternal)
		return nil
	}
	if req.WalletType == mcomm.WalletType_DouWallet {
		c, wallet := UccMgr().DouWalletImResultBet(req)
		res.Code = int32(c)
		if c == 0 {
			res.Balance = wallet.Balance
			res.Wv = wallet.Wv
		}
	} else {
	}
	return nil
}

func (s *UCService) Bet(ctx context.Context, req *statement.PlayBet, res *user.BalanceRet) error {
	b, err := proto.Marshal(req)
	if err != nil {
		logger.Error("[UC] create bet fail on proto.Marshal", zap.Uint64("BetId", req.BetId), zap.Error(err))
		res.Code = int32(response.ErrInternal)
		return nil
	}
	var subject string
	if req.GameId == gamep.AviatorGameId {
		subject = constant.SubjectAvtBet
	} else {
		subject = constant.SubjectImBet
	}
	if !gmq.Publish(subject, b) {
		res.Code = int32(response.ErrInternal)
		return nil
	}
	if req.WalletType == mcomm.WalletType_DouWallet {
		c, wallet := UccMgr().DouWalletBet(req)
		res.Code = int32(c)
		if c == 0 {
			res.Balance = wallet.Balance
			res.Wv = wallet.Wv
		}
	} else {
	}
	return nil
}

func (s *UCService) Payout(ctx context.Context, req *statement.PlayPayout, res *user.BalanceRet) error {
	b, err := proto.Marshal(req)
	if err != nil {
		logger.Error("[UC] create bet payout fail on proto.Marshal", zap.Uint64("BetId", req.BetId), zap.Error(err))
		res.Code = int32(response.ErrInternal)
		return nil
	}
	var subject string
	if req.GameId == gamep.AviatorGameId {
		subject = constant.SubjectAvtPayout
	} else {
		subject = constant.SubjectBetPayout
	}
	if !gmq.Publish(subject, b) {
		res.Code = int32(response.ErrInternal)
		return nil
	}
	c, winAmt := UccMgr().DouWalletPayout(req)
	res.Code = int32(c)
	if c == 0 {
		res.Balance = winAmt
	}
	return nil
}

func (s *UCService) BetCancel(ctx context.Context, req *statement.PlayCancel, res *user.BalanceRet) error {
	b, err := proto.Marshal(req)
	if err != nil {
		logger.Error("[UC] create bet cancel fail on proto.Marshal", zap.Uint64("BetId", req.BetId), zap.Error(err))
		res.Code = int32(response.ErrInternal)
		return nil
	}
	var subject string
	if req.GameId == gamep.AviatorGameId {
		subject = constant.SubjectAvtCancel
	} else {
		subject = constant.SubjectBetCancel
	}
	if !gmq.Publish(subject, b) {
		res.Code = int32(response.ErrInternal)
		return nil
	}
	c, amt := UccMgr().DouWalletBetCancel(req)
	res.Code = int32(c)
	if c == 0 {
		res.Balance = amt
	}
	return nil
}

func (s *UCService) PlayInput(ctx context.Context, req *statement.PlayBet, res *mcomm.CodeRet) error {
	req.PreData = true
	b, err := proto.Marshal(req)
	if err != nil {
		logger.Error("[UC] create bet input data fail on proto.Marshal", zap.Uint64("BetId", req.BetId), zap.Uint64("Uid", req.Uid), zap.Int32("GameAct", int32(req.GameAct)), zap.Error(err))
		res.Code = int32(response.ErrInternal)
		return nil
	}
	gmq.PublishAsync(constant.SubjectBetIpt, b)
	return nil
}

func (s *UCService) BetStep(ctx context.Context, req *statement.PlayStep, res *mcomm.CodeRet) error {
	b, err := proto.Marshal(req)
	if err != nil {
		logger.Error("[UC] create bet step fail on proto.Marshal", zap.Uint64("BetId", req.BetId), zap.Error(err))
		res.Code = int32(response.ErrInternal)
		return nil
	}
	if !gmq.Publish(constant.SubjectStepBet, b) {
		res.Code = int32(response.ErrInternal)
		return nil
	}
	c := UccMgr().DouWalletBetStep(req)
	res.Code = int32(c)

	return nil
}

func (s *UCService) UpBetPendingSettle(ctx context.Context, req *statement.SettleStmList, res *mcomm.CodeRet) error {
	b, err := proto.Marshal(req)
	if err != nil {
		logger.Error("[UC] create bet settle fail on proto.Marshal", zap.Int64("NodeId", req.NodeId), zap.Error(err))
		res.Code = int32(response.ErrInternal)
		return nil
	}
	var idsArr []string
	for _, item := range req.States {
		idsArr = append(idsArr, strconv.FormatUint(item.BetId, 10))
	}
	var subject string
	if req.GType == 1 {
		subject = constant.SubjectAvtLoseStm
	} else {
		subject = constant.SubjectSettleStm
	}
	if !gmq.Publish(subject, b) {
		res.Code = int32(response.ErrInternal)
		return nil
	}
	var c int16
	if req.GType == 1 {
		c = UccMgr().AvtLoseSettle(strings.Join(idsArr, ","), req.NodeId)
	} else {
		c = UccMgr().BetStmSettled(strings.Join(idsArr, ","), req.NodeId)
	}
	res.Code = int32(c)
	return nil
}

func (s *UCService) NodeStartSettledStmDeal(ctx context.Context, req *statement.NodeStartStmSettle, res *statement.NodeStartStmSettleReply) error {
	code, dealNum, lastBetId := UccMgr().DoNodeStartSettledStm(req)
	res.Code = int32(code)
	res.LastBetId = lastBetId
	res.DealCount = dealNum
	return nil
}
